package com.bussiness.system.util;

import org.joda.time.DateTime;
import org.joda.time.Interval;
import org.joda.time.Period;
import org.springframework.util.Assert;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author xlr
 * @email liru@tengyue360
 * @date 2018-08-11 13:06:22
 */
public class DateUtil {

    
    public enum Formatter{
        /**
         * yyyy-MM-dd
         */
        YEAR_TO_DAY,
        /**
         * yyyy-MM-dd HH
         */
        YEAR_TO_HOUR,
        /**
         * yyyy-MM-dd HH:mm
         */
        YEAR_TO_MINUTE,
        /**
         * yyyy-MM-dd HH:mm:ss
         */
        YEAR_TO_SECOND,

        /**
         * yyyy-MM-dd HH:mm:ss:sss
         */
        YEAR_TO_MILLISECOND,
        /**
         * yyyyMMdd
         */
        YEAR$TO$DAY,
        /**
         *yyyyMMddHHmmss
         */
        YEAR$TO$SECOND,
        /**
         *yyyyMMddHHmmssSSS
         */
        YEAR$TO$MILLISECOND,
        /**
         *yyyyMM
         */
        YEAR$METHOD,
        /**
         *yyyy
         */
        YEAR,
        /**
         *MMddhhmmss
         */
        METHOD$SECOND,
        /**
         *yyyy年MM月dd日
         */
        YEAR$TO$DAY_ZH,
        /**
         * yyyy年MM月dd日 HH时mm分ss秒
         */
        YEAR$TO$SECOND_ZH;
    }

    private static Map<Object,Object> map = new ConcurrentHashMap <>(  );

    private static Map<Formatter,SimpleDateFormat> formatterMap = new HashMap<Formatter,SimpleDateFormat>();

    public static final SimpleDateFormat YEAR_TO_DAY =new SimpleDateFormat("yyyy-MM-dd");

    public static final SimpleDateFormat YEAR_TO_HOUR = new SimpleDateFormat("yyyy-MM-dd HH");

    public static final SimpleDateFormat YEAR_TO_MINUTE = new SimpleDateFormat("yyyy-MM-dd HH:mm");

    public static final SimpleDateFormat YEAR_TO_SECOND = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static final SimpleDateFormat YEAR_TO_MILLISECOND= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:sss");

    public static final SimpleDateFormat YEAR$TO$DAY = new SimpleDateFormat("yyyyMMdd");

    public static final SimpleDateFormat YEAR$TO$SECOND = new SimpleDateFormat("yyyyMMddHHmmss");

    public static final SimpleDateFormat YEAR$TO$MILLISECOND = new SimpleDateFormat("yyyyMMddHHmmssSSS");

    public static final SimpleDateFormat YEAR$METHOD = new SimpleDateFormat("yyyyMM");

    public static final SimpleDateFormat YEAR = new SimpleDateFormat("yyyy");

    public static final SimpleDateFormat METHOD$SECOND = new SimpleDateFormat("MMddhhmmss");

    public static final SimpleDateFormat YEAR$TO$DAY_ZH = new SimpleDateFormat("yyyy年MM月dd日");

    public static final SimpleDateFormat YEAR$TO$SECOND_ZH = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");

    static{
        formatterMap.put(Formatter.YEAR_TO_DAY, YEAR_TO_DAY);
        formatterMap.put(Formatter.YEAR_TO_HOUR, YEAR_TO_HOUR);
        formatterMap.put(Formatter.YEAR_TO_MINUTE, YEAR_TO_MINUTE);
        formatterMap.put(Formatter.YEAR_TO_SECOND, YEAR_TO_SECOND);
        formatterMap.put(Formatter.YEAR_TO_MILLISECOND, YEAR_TO_MILLISECOND);
        formatterMap.put(Formatter.YEAR$TO$DAY, YEAR$TO$DAY);
        formatterMap.put(Formatter.YEAR$TO$SECOND, YEAR$TO$SECOND);
        formatterMap.put(Formatter.YEAR$TO$MILLISECOND, YEAR$TO$MILLISECOND);
        formatterMap.put(Formatter.YEAR$METHOD, YEAR$METHOD);
        formatterMap.put(Formatter.YEAR, YEAR);
        formatterMap.put(Formatter.METHOD$SECOND, METHOD$SECOND);
        formatterMap.put(Formatter.YEAR$TO$DAY_ZH, YEAR$TO$DAY_ZH);
        formatterMap.put(Formatter.YEAR$TO$SECOND_ZH, YEAR$TO$SECOND_ZH);

    }

    /**
     * 根据formatter指定的日期格式，日期转换字符串
     * @param date
     * @param formatter
     * @return
     */
    public final static String toFormatString(Date date,Formatter formatter){
        Assert.notNull(date);
        Assert.notNull(formatter);
        return formatterMap.get(formatter).format(date);
    }

    /**
     * 根据formatter指定的日期格式，字符串转换日期
     * @param date
     * @param formatter
     * @return Date
     */
    public final static Date toFormatDate(String date,Formatter formatter){
        try {
            return formatterMap.get(formatter).parse( date );
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据formatter指定的日期格式，字符串转换日期
     * @param date
     * @param formatter 需要的格式
     * @return
     */
    public final static String toFormatString(Date date,String formatter){
        SimpleDateFormat sdf = null;
        if(map.get( formatter ) == null){
            sdf = new SimpleDateFormat( formatter );
            map.put( formatter,sdf );
        }else{
            sdf = (SimpleDateFormat)map.get( formatter );
        }
        return sdf.format( date );
    }


    /**
     * 根据formatter指定的日期格式，字符串转换日期 默认格式 yyyy-MM-dd
     * @param date
     * @return Date
     */
    public final static Date toFormatDateTime(String date){

        try {
            return YEAR_TO_DAY.parse(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 增加year年，返回一个new Date。
     * @param date
     * @param year
     * @return
     */
    public final static Date addYear(Date date,int year){
        return new DateTime(date.getTime()).plusYears(year).toDate();
    }

    /**
     * 增加月，返回一个new date
     * @param date
     * @param month
     * @return
     */
    public final static Date addMonth(Date date,int month){
        return new DateTime(date.getTime()).plusMonths(month).toDate();
    }

    /**
     * 增加日，返回一个new date
     * @param date
     * @param day
     * @return
     */
    public final static Date addDay(Date date,int day){
        return new DateTime(date.getTime()).plusDays(day).toDate();
    }

    /**
     * 增加小时，返回一个new date
     * @param date
     * @param hour
     * @return
     */
    public final static Date addHour(Date date,int hour){
        return new DateTime(date.getTime()).plusHours(hour).toDate();
    }

    /**
     * 增加分，返回一个new date
     * @param date
     * @param minute
     * @return
     */
    public final static Date addMinute(Date date,int minute){
        return new DateTime(date.getTime()).plusMinutes(minute) .toDate();
    }


    /**
     * 增加秒，返回一个new date
     * @param date
     * @param second
     * @return
     */
    public final static Date addSecond(Date date,int second){
        return new DateTime(date.getTime()).plusSeconds(second) .toDate();
    }

    /**
     * 获取两个date之间的差值（精确到日）
     * @param start
     * @param end
     * @return Period
     */

    public final static Period getPeriod(Date start, Date end){
        Assert.notNull(start);
        Assert.notNull(end);
        Interval interval = null;
        if(!start.after( end )){
            interval = new Interval(new DateTime(start.getTime()),new DateTime(end.getTime()));
            return interval.toPeriod();
        }
        return null;
    }

    /**
     * 获取两个datetime之间的差值
     * @param start
     * @param end
     * @return Period
     */

    public final static Period getPeriod(DateTime start,DateTime end){
        Assert.notNull(start);
        Assert.notNull(end);
        try {
            Interval interval = new Interval(start,end);
            return interval.toPeriod();
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取start与nowTI相差天数
     * @param start
     * @return days
     */

    public final static long getDays(String start,long nowTime){
        Assert.notNull(start);
        long from = 0;
        try {
            from = new SimpleDateFormat("yyyy-MM-dd").parse(start).getTime();
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return (nowTime - from)/(1000*60*60*24);
    }

    /**
     * 获取两个date之间相差天数
     * @param start
     * @param end
     * @return
     */
    public final static long getDurationDays(Date start,Date end){
        Assert.notNull(start);
        Assert.notNull(end);
        Interval interval = new Interval(new DateTime(start.getTime()),new DateTime(end.getTime()));
        return interval.toDuration().getStandardDays();
    }
}

